﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary.Statistics.Distribution
{
    /// <summary>
    /// This class represents a Weibull distribution.
    /// </summary>
    [Serializable]
    public class WeibullDistribution
    {
        /// <summary>
        /// The scale parameter of the distribution.
        /// </summary>
        private readonly double scale;

        /// <summary>
        /// The shape parameter of the distribution.
        /// </summary>
        private readonly double shape;

        /// <summary>
        /// Initializes a new instance of the <see cref="WeibullDistribution"/> class.
        /// </summary>
        /// <param name="shape">The shape parameter of the distribution.</param>
        /// <param name="scale">The scale parameter of the distribution.</param>
        public WeibullDistribution(double shape, double scale)
        {
            if (scale <= 0)
            {
                throw new ArgumentException("scale <= 0");
            }

            if (shape <= 0)
            {
                throw new ArgumentException("shape <= 0");
            }

            this.scale = scale;
            this.shape = shape;
        }

        /// <summary>
        /// Gets the scale parameter of the distribution.
        /// </summary>
        /// <value>The scale parameter of the distribution.</value>
        public double Scale
        {
            get { return this.scale; }
        }

        /// <summary>
        /// Gets the shape parameter of the distribution.
        /// </summary>
        /// <value>The shape parameter of the distribution.</value>
        public double Shape
        {
            get { return this.shape; }
        }

        /// <summary>
        /// Gets the mean of the distribution.
        /// </summary>
        /// <value>The mean of the distribution.</value>
        public double Mean
        {
            get { return (scale*SpecialFunctions.GammaFunction(1.0 + 1.0/this.shape)); }
        }

        /// <summary>
        /// Gets the median of the distribution.
        /// </summary>
        /// <value>The median of the distribution.</value>
        public double Median
        {
            get { return (this.scale*Math.Pow(Math.Log(2.0), 1.0/this.shape)); }
        }

        /// <summary>
        /// Computes the probability mass function of the Weibull distribution at the specified postion x.
        /// </summary>
        /// <param name="x">The specified position x.</param>
        /// <returns>The probability mass function of the Weibull distribution at the specified postion x.</returns>
        public double ProbabilityMassFunction(double x)
        {
            if (x < 0)
            {
                return 0;
            }

            return (this.scale/this.shape)*Math.Pow(x/this.shape, this.scale - 1)*
                   Math.Pow(Math.E, -Math.Pow((x/this.shape), this.scale));
        }

        /// <summary>
        /// Computes the cumulative distribution function of the Weibull distribution at the specified postion x.
        /// </summary>
        /// <param name="x">The specified position x.</param>
        /// <returns>The cumulative distribution function of the Weibull distribution at the specified postion x.</returns>
        public double CumulativeDistributionFunction(double x)
        {
            return 1 - Math.Pow(Math.E, -Math.Pow(x/this.shape, this.scale));
        }
    }
}